package tk.capkiller.sharelinks.biz;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

public class GridCounter {

	private BufferedImage myImage;
	private BufferedImage originalImage;

	private boolean searchForHigh = false;

	// for searching Rows
	private final int xToleranzHigh = 5;
	private final int xToleranzLow = 1;
	private final int xStart = 0;
	private final int xEnd = 0;
	private int scanSizeColX = 5;// 5!
	private int scanSizeColY = 100;// myImage.getHeight()!
	private final int xreduceScanSizeAfterColNr = 6;
	private int xReducedScanSize = 2;

	// for searching Columns
	private final int yToleranzHigh = 5;
	private final int yToleranzLow = 2;// 1
	private final int yStart = 0;
	private final int yEnd = 0;
	private final int scanSizeRowY = 1;
	private int scanSizeRowX = 100;// myImage.getWidth()!
	private ArrayList<Point> colWidths; // Point(start,end)
	private ArrayList<Point> rowWidths;// Point(start,end)
	private int minimumSpace = 10;
	private int lastXY;
	private ValuesInAGrid grid;
	public static final char[] LETTERS;

	static {
		LETTERS = new char[26];
		LETTERS[0] = 'A';
		LETTERS[1] = 'B';
		LETTERS[2] = 'C';
		LETTERS[3] = 'D';
		LETTERS[4] = 'E';
		LETTERS[5] = 'F';
		LETTERS[6] = 'G';
		LETTERS[7] = 'H';
		LETTERS[8] = 'I';
		LETTERS[9] = 'J';
		LETTERS[10] = 'K';
		LETTERS[11] = 'L';
		LETTERS[12] = 'M';
		LETTERS[13] = 'N';
		LETTERS[14] = 'O';
		LETTERS[15] = 'P';
		LETTERS[16] = 'Q';
		LETTERS[17] = 'R';
		LETTERS[18] = 'S';
		LETTERS[19] = 'T';
		LETTERS[20] = 'U';
		LETTERS[21] = 'V';
		LETTERS[22] = 'W';
		LETTERS[23] = 'X';
		LETTERS[24] = 'Y';
		LETTERS[25] = 'Z';
	}

	public static int getRowForLetter(char letter) {
		for (int i = 0; i < LETTERS.length; i++) {
			if (LETTERS[i] == letter) {
				return i;
			}
		}
		return 0;
	}

	public GridCounter(BufferedImage pImage) {
		// this.inputImage = EasyImage.isolateImage(pImage,
		// EasyImage.COLOR_NUMBER_SMALL, 50);// 250
		this.originalImage = pImage;
		this.myImage = EasyImage.makeEasy(pImage, 50,
				BufferedImage.TYPE_BYTE_GRAY);
		scanSizeColY = myImage.getHeight();
		scanSizeRowX = myImage.getWidth();
		CaptchaBreaker.testWriteImage(myImage, "C:\\temp\\countInput.gif");
		grid = new ValuesInAGrid();
		colWidths = new ArrayList<Point>();
		rowWidths = new ArrayList<Point>();
	}

	// how many rows?
	private int countRows() {
		int rows = 0;
		lastXY = 0;
		minimumSpace = 0;
		searchForHigh = true;
		int y = yStart;
		while (y + scanSizeRowY < myImage.getHeight() - yEnd) {
			int scan = EasyImage.countPixelWithOtherColors(
					(myImage.getSubimage(0, y, scanSizeRowX, scanSizeRowY)),
					EasyImage.TRANSPARENT_BGCOLOR);
			rows = updateRow(scan, rows, yToleranzLow, yToleranzHigh, y);
			y++;

		}
		if (!searchForHigh) {// rand zu schmal unter letzter zeile
			rowWidths.add(new Point(this.lastXY, y + 1));
		}
		rowWidths.trimToSize();
		return rowWidths.size();
	}

	// how many cols?
	private int countCols() {
		int cols = 0;
		lastXY = 0;
		minimumSpace = 0;
		searchForHigh = true;
		int x = xStart;
		while (x + scanSizeColX < myImage.getWidth() - xEnd) {
			int scan = EasyImage.countPixelWithOtherColors(
					(myImage.getSubimage(x, 0, scanSizeColX, scanSizeColY)),
					EasyImage.TRANSPARENT_BGCOLOR);
			cols = updateCol(scan, cols, xToleranzLow, xToleranzHigh, x);

			x++;
			// after some cols (xAppendScanSizeAfterColNr) each img will need
			// more space;
			if (cols == xreduceScanSizeAfterColNr) {
				scanSizeColX = xReducedScanSize;
			}
		}

		if (!searchForHigh) {// rand zu schmal unter letzter zeile
			colWidths.add(new Point(this.lastXY, x + 1));
		}
		colWidths.trimToSize();
		return colWidths.size();
	}

	private void updateGrid() {
		int width;
		int height;
		int startX;
		int startY;
		for (int c = 0; c < colWidths.size(); c++) {
			for (int r = 0; r < rowWidths.size(); r++) {
				startX = colWidths.get(c).x;
				width = colWidths.get(c).y - startX;
				startY = rowWidths.get(r).x;
				height = rowWidths.get(r).y - startY;
				BufferedImage img = new BufferedImage(width, height,
						BufferedImage.TYPE_BYTE_GRAY);
				Graphics2D gfx = img.createGraphics();
				gfx.drawImage(
						myImage.getSubimage(startX, startY, width, height), 0,
						0, null);
				// img = EasyImage.reduceColors(img,
				// BufferedImage.TYPE_BYTE_GRAY);
				// img = EasyImage.isolateImage(img, Color.BLACK, 0, false);
				// Point start = EasyImage.getCornerLeft(img, Color.BLACK,
				// false);
				// EasyImage.fill8(img, start.x, start.y, Color.WHITE.getRGB(),
				// Color.BLACK.getRGB());
				// img = EasyImage.cutImage(img, Color.BLACK, Color.WHITE);
				img = EasyImage.deleteLetter(img);
				CompareImage compImage = new CompareImage(img,
						new StringIntegerPair(String.valueOf(LETTERS[r]), 0));
				compImage.setTopLeftCut(new Point(startX, startY));
				compImage.setButtomRightCut(new Point(startX + width, startY
						+ height));
				grid.add(compImage, r, c);
			}
		}
		grid.trimToSize();
		System.gc();
	}

	private int updateRow(int scan, int row, int toleranzLow,
			int toleranzHeight, int y) {
		int rows = updateRowCol(scan, row, toleranzLow, toleranzHeight, y);
		if (row != rows) {
			rowWidths.add(new Point(this.lastXY, y + 1));
			this.lastXY = y + 1;
		}
		return rows;
	}

	private int updateCol(int scan, int col, int toleranzLow,
			int toleranzHeight, int x) {

		int cols = updateRowCol(scan, col, toleranzLow, toleranzHeight, x);
		if (col != cols) {
			colWidths.add(new Point(this.lastXY, x + 1));
			this.lastXY = x + 1;
		}
		return cols;
	}

	private int updateRowCol(int scan, int colRow, int toleranzLow,
			int toleranzHeight, int xyPos) {
		boolean result;
		boolean isLow = scan <= toleranzLow;
		boolean isHigh = scan > toleranzHeight;
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println(xyPos + " Diff: " + scan);
		if (searchForHigh) {
			result = isHigh;
			if (result && colRow == 0) {
				this.lastXY = xyPos;
			}
		} else {
			result = isLow;
			if (result && colRow == 0) {
				minimumSpace = xyPos - this.lastXY;
			}
		}

		if ((result && !searchForHigh) && xyPos - this.lastXY >= minimumSpace) {
			colRow++;
			if (CaptchaBreaker.DEBUG_MODE)
				System.out.println("new Col/Row " + colRow + " @ " + xyPos
						+ " (Diff: " + scan + ")");
		}
		searchForHigh = result ? !searchForHigh : searchForHigh;

		return colRow;
	}

	public ValuesInAGrid countGrid() {
		Point result = new Point(12, 15);
		result.x = 0;
		result.y = 0;
		// Point result = new Point(13, 9);
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println("########### Rows: ################");
		result.y = countRows();
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println("########### Rows: " + result.y
					+ "##############");
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println("########### Cols: ################");
		result.x = countCols();
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println("########### Cols: " + result.x
					+ "##############");
		if (CaptchaBreaker.DEBUG_MODE)
			System.out.println("Grid: " + result.x + "x" + result.y);

		updateGrid();
		return grid;
	}

}